package com.lemon.exam.common.handler;

import com.alibaba.fastjson2.JSON;
import com.lemon.exam.common.annotation.NoResult;
import com.lemon.exam.common.properties.ConfigProperties;
import com.lemon.exam.common.web.Result;
import lombok.Getter;
import lombok.Setter;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.annotation.NonNull;

/**
 * 全局响应结果处理器，处理返回结果，也就是响应Result对象
 *
 * @author Lemon
 * @since 2025/2/17 16:11
 */
@Setter
@Getter
@Component
public class GlobalResponseHandler extends ResponseBodyResultHandler {

    private ConfigProperties properties;

    public GlobalResponseHandler(ServerCodecConfigurer configurer, RequestedContentTypeResolver resolver, ConfigProperties properties) {
        super(configurer.getWriters(), resolver);
        this.properties = properties;
    }

    @Override
    @SuppressWarnings("all")
    public boolean supports(@NonNull HandlerResult result) {
        //获取方法上的注解
        NoResult noResult = result.getReturnTypeSource().getMethodAnnotation(NoResult.class);
        return noResult == null;
    }

    @Override
    @NonNull
    public Mono<Void> handleResult(@NonNull ServerWebExchange exchange, @NonNull HandlerResult result) {
        //1.响应状态是否成功
        boolean successful = exchange.getResponse().getStatusCode().is2xxSuccessful();
        //2.判断是否需要处理返回结果
        final String uri = exchange.getRequest().getPath().toString();
        boolean match = properties.getKnife4jIgnoreUri().parallelStream().anyMatch(item -> (item.endsWith("/**") && uri.startsWith(item.substring(0, item.length() - 2))) || uri.equals(item));
        if (!successful || match) {
            return super.writeBody(result.getReturnValue(), result.getReturnTypeSource(), exchange);
        }
        //3.处理返回结果
        return Mono.justOrEmpty(result.getReturnValue()).flatMap(value -> {
            if (value instanceof Mono) {
                return ((Mono<?>) value).flatMap(v -> writeBody(v, result.getReturnTypeSource(), exchange));
            } else if (value instanceof Flux) {
                return ((Flux<?>) value).collectList().flatMap(v -> writeBody(v, result.getReturnTypeSource(), exchange));
            } else {
                return super.writeBody(value, result.getReturnTypeSource(), exchange);
            }
        });
    }

    @Override
    @NonNull
    protected Mono<Void> writeBody(@NonNull Object body, @NonNull MethodParameter bodyParameter, @NonNull ServerWebExchange exchange) {
        //1.设置响应类型为JSON
        exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
        if (body instanceof Result) {
            return super.writeBody(JSON.toJSON(body), bodyParameter, exchange);
        } else {
            return super.writeBody(JSON.toJSON(Result.ok(body)), bodyParameter, exchange);
        }
    }
}
